﻿
#ifndef MYQUEUE_H_  
#define MYQUEUE_H_  
#include <deque>
#include <pthread.h>
using namespace std;

class auto_lock {
public:
	auto_lock(pthread_mutex_t  &mutex) {
		this->mutex = mutex;
		pthread_mutex_lock(&(this->mutex));
	}
	~auto_lock() {
		pthread_mutex_unlock(&(this->mutex));
	}
private:
		pthread_mutex_t  mutex;
};

template<class DataType>
class MyQueue {
public:
	MyQueue()  {
		pthread_mutex_init(&_not_full_mutex, NULL);
		pthread_mutex_init(&_size, NULL);
		pthread_mutex_init(&_not_empty_mutex, NULL);
		pthread_cond_init(&_not_empty_cond, NULL);
	}

	int push(DataType d) {
		pthread_mutex_lock(&_not_full_mutex);
		_queue.push_back(d);
		pthread_cond_signal(&_not_empty_cond);
		pthread_mutex_unlock(&_not_full_mutex);
		return 0;
	}

	int pop(DataType &d) {
		pthread_mutex_lock(&_not_empty_mutex);
		while (isEmpty())
			pthread_cond_wait(&_not_empty_cond, &_not_empty_mutex);
		d = _queue.front();
		_queue.pop_front();
		pthread_mutex_unlock(&_not_empty_mutex);
		return 0;
	}

	int size() {
		auto_lock my_lock(this->_not_empty_mutex);
		auto_lock my_lock(this->_not_full_mutex);
		return this->_queue.size();
	}
	bool isEmpty() {
		auto_lock my_lock(this->_size);
		if (this->_queue.size() == 0)
			return true;
		else
			return false;
	}
private:
	pthread_mutex_t _not_full_mutex;
	pthread_mutex_t _size;
	pthread_mutex_t _not_empty_mutex;
	pthread_cond_t _not_empty_cond;
	deque<DataType> _queue;
};

#endif /* QUEUE_H_ */  